/*****************************************************************
*
*	Netcare Agent Project
*		Copyright(C) 2010, Wicresoft EKA. All Rights Reserved.
*
*	Authors:
*		Miles Chen (milesch@wicresoft.com)
*		TingRong Shi (trshi@wicresoft.com)
*
*	Part of the product code depends on gSOAP under GPL license
*		Copyright(C) 2000-2010, Robert van Engelen, Genivia Inc. All Rights Reserved.
*
*****************************************************************/
#ifdef WIN32
// Windows
#include <Windows.h>
#include <Winternl.h>
#include <tlhelp32.h>
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
#else
// Linux
#include <stdio.h>
#include <glib.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <ctype.h>
#include <fstream>
#include <string.h>
#include <iostream>
#endif


#include "Process.h"



NETCARE_AGENT;

#define PS_MAX_PATH	1024
#define PS_MAX_MODS	64
#define PS_MAX_IMAGE	64

CProcess::CProcess(unsigned int pid) : 
	ProcessId(pid),
	NonpagedSystemMemorySize64(0),
	PagedMemorySize64(0),
	PeakPagedMemorySize64(0),
	PeakVirtualMemorySize64(0),
	PrivateMemorySize64(0)
{
#ifdef WIN32
	// Windows
	HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, TRUE, pid );
	if(hProcess)
	{
		HMODULE hMods[PS_MAX_MODS];
		DWORD cb;
		int len;

		BOOL ret = EnumProcessModules(hProcess, hMods, PS_MAX_MODS, &cb);

		PROCESS_MEMORY_COUNTERS memoryInfo;
		memoryInfo.cb = sizeof(PROCESS_MEMORY_COUNTERS);
		if(::GetProcessMemoryInfo(hProcess, &memoryInfo, sizeof(memoryInfo)))
		{
			NonpagedSystemMemorySize64 = memoryInfo.QuotaNonPagedPoolUsage;
			PagedMemorySize64 = memoryInfo.PagefileUsage;
			PeakPagedMemorySize64 = memoryInfo.PeakPagefileUsage;
			PeakVirtualMemorySize64 = memoryInfo.PeakWorkingSetSize;
		}
		ImageName.resize(PS_MAX_IMAGE);
		len = GetModuleBaseNameW(hProcess, hMods[0], (wchar_t*)ImageName.c_str(), PS_MAX_IMAGE);
		if(len)
			ImageName.resize(len);
		FullPath.resize(PS_MAX_PATH);

		len = GetModuleFileNameExW(hProcess, hMods[0], (wchar_t*)FullPath.c_str(), PS_MAX_PATH);
		if(len)
			FullPath.resize(len);
		
		

		CloseHandle(hProcess);
	}
	else
	{
		ImageName = L"<Access is denied>";
	}
#else
	// Linux
	char a[PS_MAX_PATH],b[PS_MAX_PATH],buffer[PS_MAX_PATH];
	char proute1[PS_MAX_PATH] = "/proc/";
	char proute3[] = "/status";
	char route[] = "/exe";
	char proute2[PS_MAX_PATH];
	sprintf(proute2, "%d", ProcessId);
	char sroute1[PS_MAX_PATH] = "/proc/";
	char sroute3[] = "/exe";
	char sroute2[PS_MAX_PATH];
	sprintf(sroute2, "%d", ProcessId);
	char* spid = strcat(proute1,strcat(proute2,proute3));
	char* sroute = strcat(sroute1,strcat(sroute2,sroute3));
	ifstream openProc(spid);
	if(!openProc.is_open())
	{
		ImageName = "<Access is denied>";
	}
	else
	{
		while(openProc.getline(buffer,256))
		{
			sscanf(buffer,"%s %s",a,b);
			if((string)a=="Name:")
			  ImageName=(string)b;
			if((string)a=="VmPeak:")
			  PeakVirtualMemorySize64=atol(b);
		}
		char buf[PS_MAX_PATH];
		int count = readlink(sroute,buf,PS_MAX_PATH);
		buf[count] = '\0';
		if(0<=count && count<=PS_MAX_PATH)
		{
			FullPath = buf;
		}
		
	}
	openProc.close();
#endif

}


CProcess::~CProcess(void)
{
}

vector<CProcess*>* CProcess::GetProcesses()
{

#ifdef WIN32
// Windows
	
	DWORD aProcesses[2048], cbNeeded, cProcesses;
    unsigned int i;
	if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return NULL;
	cProcesses = cbNeeded / sizeof(DWORD);
	vector<CProcess*>* list = new vector<CProcess*>();
	for ( i = 0; i < cProcesses; i++ )
        if( aProcesses[i] != 0 )
            list->push_back(new CProcess(aProcesses[i]));

	return list;
#else
// Linux
	///get processes ids
	guint32 pids[1024];
	//guint32 *needed;
	guint32 len = sizeof(pids);
	GArray *processes = g_array_new (FALSE, FALSE, sizeof(pid_t));
	guint32 fit,i=0, j=0;
	DIR *dir;
	struct dirent *entry;
	
	//mono_once (&process_current_once, process_set_current);

	dir = opendir ("/proc");
	if (dir == NULL) {
		return NULL;
	}
	while((entry = readdir (dir)) != NULL) {
		if (isdigit (entry->d_name[0])) {
			char *endptr;
			pid_t pid = (pid_t)strtol (entry->d_name, &endptr, 10);

			if (*endptr == '\0') {
				/* Name was entirely numeric, so was a
				 * process ID
				 */
				g_array_append_val (processes, pid);
			}
		}
	}
	closedir (dir);
	fit=len/sizeof(guint32);
	while(i < processes->len && j<fit )
	{
		pids[j++] = g_array_index (processes, pid_t, i);
		i++;
	}
	g_array_free (processes, TRUE);
	//*needed = j * sizeof(guint32);
	//get processes informations
	vector<CProcess*>* list = new vector<CProcess*>();
	for (int index = 0; index < j; index++) {
				
		list->push_back (new CProcess ((unsigned long)pids [index]));
		}
	
	return list;
#endif

}


bool CProcess::Kill() const
{
#ifdef WIN32
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
	if(hProcess)
	{
		bool ret = (bool)TerminateProcess(hProcess, -1);
		CloseHandle(hProcess);
		return ret;
	}
	else
	{
		return false;
	}
#else
	if(!kill(ProcessId,SIGABRT))
		return true;
	else
		return false;
#endif
}


ENDNS ENDNS